home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / a_utils / _archvrs / unix / unzip51 / unzip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-04  |  47.5 KB  |  1,276 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   unzip.c
  4.  
  5.   UnZip - a zipfile extraction utility.  See below for make instructions, or
  6.   read the comments in Makefile and the various Contents files for more de-
  7.   tailed explanations.  To report a bug, send a *complete* description to
  8.   zip-bugs@cs.ucla.edu; include machine type, operating system and version,
  9.   compiler and version, and reasonably detailed error messages or problem
  10.   report.  To join Info-ZIP, send a message to izip-mgr@wkuvx1.bitnet (or
  11.   izip-mgr%wkuvx1.bitnet@ukcc.uky.edu).
  12.  
  13.   UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x,
  14.   which in turn was almost a complete rewrite of version 3.x.  For a detailed
  15.   revision history, see UnzpHist.zip at quest.jpl.nasa.gov.  For a list of
  16.   the many (near infinite) contributors, see "CONTRIBS" in the UnZip source
  17.   distribution.
  18.  
  19.   ---------------------------------------------------------------------------
  20.  
  21.   To compile (partial instructions):
  22.  
  23.      under Unix (cc):  make <system name>
  24.        (type "make list" for a list of valid names, or read Makefile for 
  25.        details.  "make unzip" works for most systems.  If you have a NEW
  26.        system, not covered by any of the existing targets, send FULL infor-
  27.        mation--hardware, OS, versions, etc.--to zip-bugs@cs.ucla.edu)
  28.  
  29.      under VMS (VAX C or GNU C):  @make_vaxc_unzip  or  @make_gcc_unzip
  30.        (from VMS sub-archive; can also use MMS or MAKE/VMS; see VMS.notes)
  31.  
  32.      under OS/2 (MSC, gcc, IBM C Set/2, Watcom C):  make -f makefile.os2
  33.        (from OS2 sub-archive; for MSC, use NMAKE)
  34.  
  35.      under MS-DOS (MSC, Turbo C, or Borland C++):  use the makefiles or
  36.        project files in the MSDOS sub-archive; edit or otherwise modify
  37.        as appropriate.  For MSC, use NMAKE.
  38.  
  39.      under MS Windows 3.1:  get wunz13sr.{zip | zoo | whatever} and use
  40.        the included makefile
  41.  
  42.      under Windows NT:  use makefile.nt (from NT sub-archive)
  43.  
  44.      under Macintosh OS:  double click on unzip.make; press <Command>-M
  45.        (from MAC sub-archive)
  46.  
  47.      under AmigaDOS:  lmk -f amiga/LMKFile all (from AMIGA sub-archive;
  48.        see also MakeScript)
  49.  
  50.      under TOPS-20:  use make.mic and "do make"
  51.  
  52.      under Atari TOS:  needs considerable work yet...
  53.  
  54.   ---------------------------------------------------------------------------
  55.  
  56.   Version:  unzip51.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
  57.               Windows NT, Macintosh, Amiga and TOPS-20.  Decryption requires
  58.               sources in zcrypt20.zip, and Windows (not NT) support requires
  59.               sources in wunz13sr.zip.  See accompanying file "Where" in the
  60.               main source distribution for ftp, uucp and mail-server sites.
  61.   Copyrights:  see accompanying file "COPYING" in UnZip source distribution.
  62.  
  63.   ---------------------------------------------------------------------------*/
  64.  
  65.  
  66.  
  67.  
  68.  
  69. #include "unzip.h"               /* includes, typedefs, macros, etc. */
  70. #include "crypt.h"
  71. #ifdef MSWIN
  72. #  include "wizunzip.h"
  73. #endif
  74.  
  75. /* #define RELEASE */
  76. #ifdef RELEASE
  77. #  define VERSION  "v5.0 of 21 August 1992"    /* official release version */
  78. #else
  79. #  define VERSION  "v5.1d BETA of 22 Oct 92"   /* internal beta level */
  80. #endif
  81.  
  82.  
  83.  
  84.  
  85.  
  86. /**********************/
  87. /*  Global Variables  */
  88. /**********************/
  89.  
  90. int aflag=0;          /* -a: do ASCII to EBCDIC translation, or CR-LF  */
  91.                       /*     to CR or LF conversion of extracted files */
  92. /* int bflag=0; RESERVED for -b: extract as binary */
  93. int cflag=0;          /* -c: output to stdout */
  94. int fflag=0;          /* -f: "freshen" (extract only newer files) */
  95. int jflag=0;          /* -j: junk pathnames */
  96. int overwrite_none=0; /* -n: never overwrite files (no prompting) */
  97. int overwrite_all=0;  /* -o: OK to overwrite files without prompting */
  98. int force_flag=0;     /* (shares -o for now): force to override errors, etc. */
  99. int quietflg=0;       /* -q: produce a lot less output */
  100. #ifdef DOS_OS2
  101.    int sflag=1;       /* -s: allow spaces (blanks) in filenames */
  102. #endif
  103. int tflag=0;          /* -t: test */
  104. int uflag=0;          /* -u: "update" (extract only newer & brand-new files) */
  105. static int U_flag=0;  /* -U: leave filenames in upper or mixed case */
  106. static int vflag=0;   /* -v: view directory (only used in unzip.c) */
  107. int V_flag=0;         /* -V: don't strip VMS version numbers */
  108. #ifdef VMS
  109.    int secinf=0;      /* -X: keep owner/protection */
  110. #endif
  111. int zflag=0;          /* -z: display only the archive comment */
  112.  
  113. int filespecs;        /* number of real file specifications to be matched */
  114. int xfilespecs;       /* number of excluded filespecs to be matched */
  115. int process_all_files = 0;
  116. longint real_ecrec_offset, expect_ecrec_offset;
  117.  
  118. longint csize;        /* used by list_files(), ReadByte(): must be signed */
  119. longint ucsize;       /* used by list_files(), unReduce(), explode() */
  120.  
  121. static char *fnames[2] = {"*", NULL};   /* default filenames vector */
  122. char **pfnames = fnames, **pxnames = &fnames[1];
  123. char sig[5];
  124. char answerbuf[10];
  125.  
  126. min_info info[DIR_BLKSIZ], *pInfo=info;
  127.  
  128. #ifdef OS2
  129.    int longname;              /* used in extract.c, mapname.c and file_io.c */
  130.    char longfilename[FILNAMSIZ];
  131. #endif
  132.  
  133. #ifdef CRYPT
  134.    char *key = (char *)NULL;  /* password with which to decrypt data, or NULL */
  135. #endif
  136.  
  137. /*---------------------------------------------------------------------------
  138.     unShrink/unReduce/explode/inflate working storage and globals:
  139.   ---------------------------------------------------------------------------*/
  140.  
  141. union work area;              /* see unzip.h for the definition of work */
  142. ulg crc32val;
  143.  
  144. ush mask_bits[] = {
  145.     0x0000,
  146.     0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  147.     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
  148. };
  149.  
  150. /*---------------------------------------------------------------------------
  151.     Input file variables:
  152.   ---------------------------------------------------------------------------*/
  153.  
  154. uch *inbuf, *inptr;      /* input buffer (any size is legal) and pointer */
  155. int incnt;
  156.  
  157. ulg bitbuf;
  158. int bits_left;
  159. boolean zipeof;
  160.  
  161. #ifdef MSWIN
  162.    char *zipfn;
  163. #else
  164.    char zipfn[FILNAMSIZ];
  165. #endif
  166. int zipfd;               /* zipfile file handle */
  167. longint ziplen;
  168.  
  169. uch *hold;
  170. char local_hdr_sig[5] = "\120";    /* remaining signature bytes come later   */
  171. char central_hdr_sig[5] = "\120";  /*  (must initialize at runtime so unzip  */
  172. char end_central_sig[5] = "\120";  /*  executable won't look like a zipfile) */
  173. /* char extd_local_sig[5] = "\120";  NOT USED YET */
  174.  
  175. cdir_file_hdr crec;      /* used in unzip.c, extract.c, misc.c */
  176. local_file_hdr lrec;     /* used in unzip.c, extract.c */
  177. ecdir_rec ecrec;         /* used in unzip.c, extract.c */
  178. struct stat statbuf;            /* used by main, mapname, check_for_newer */
  179.  
  180. longint extra_bytes = 0;        /* used in unzip.c, misc.c */
  181. longint cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  182.   
  183. #ifdef MACOS
  184.    short  gnVRefNum;
  185.    long  glDirID;
  186.    OSType  gostCreator;
  187.    OSType  gostType;
  188.    boolean  fMacZipped;
  189.    boolean  macflag;
  190.    CursHandle  rghCursor[4];    /* status cursors */
  191.    short  giCursor = 0;
  192. #endif
  193.  
  194. /*---------------------------------------------------------------------------
  195.     Output stream variables:
  196.   ---------------------------------------------------------------------------*/
  197.  
  198. uch *outbuf;                    /* buffer for rle look-back */
  199. uch *outptr;
  200. #ifdef MSWIN
  201.    uch __far *outout;
  202.    char *filename;
  203. #else /* !MSWIN */
  204.    uch *outout;                 /* scratch pad for ASCII-native trans */
  205.    char filename[FILNAMSIZ];
  206. #endif /* ?MSWIN */
  207. uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */
  208. longint outpos;                 /* absolute position in outfile */
  209. int outcnt;                     /* current position in outbuf */
  210. int outfd;
  211. int mem_mode = 0;
  212. int disk_full;
  213. int newfile;
  214. #ifdef SYMLINKS
  215.    int symlnk;
  216. #endif
  217.  
  218. static char unkn[10];
  219. static ush methnum;
  220.  
  221. /*---------------------------------------------------------------------------
  222.     unzip.c repeated error messages (we use all of these at least twice)
  223.   ---------------------------------------------------------------------------*/
  224.  
  225. char *EndSigMsg = "\nwarning:\
  226.   didn't find end-of-central-dir signature at end of central dir.\n";
  227. char *CentSigMsg =
  228.   "error:  expected central file header signature not found (file #%u).\n";
  229. char *SeekMsg =
  230.   "error:  attempt to seek before beginning of zipfile\n%s";
  231.  
  232. #ifdef VMS
  233. char *ReportMsg = "\
  234.   (please check that you have transferred or created the zipfile in the\n\
  235.   appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
  236. #else /* !VMS */
  237. char *ReportMsg = "\
  238.   (please check that you have transferred or created the zipfile in the\n\
  239.   appropriate BINARY mode and that you have compiled unzip properly)\n";
  240. #endif /* ?VMS */
  241.  
  242.  
  243.  
  244.  
  245.  
  246. #ifdef MSWIN
  247. #  include "winsetup.c"   /* duplicates some of code in main() */
  248. #else /* !MSWIN */
  249.  
  250. /******************/
  251. /*  Main program  */
  252. /******************/
  253.  
  254. int main(argc, argv)   /* return PK-type error code (except under VMS) */
  255.     int argc;
  256.     char *argv[];
  257. {
  258.     char *s;
  259.     int c, error=FALSE, negative=0;
  260.  
  261.  
  262. #if defined(MACOS) || defined(MALLOC_WORK)
  263.     area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
  264.     area.shrink.Prefix_of = (short *)area.Slide;
  265.     area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
  266.     area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
  267. #endif
  268.  
  269. /*---------------------------------------------------------------------------
  270.     Macintosh initialization code.
  271.   ---------------------------------------------------------------------------*/
  272.  
  273. #ifdef MACOS
  274. #ifdef THINK_C
  275. #   include <console.h>
  276.     static char *argstr[30], args[30*64];
  277.     Point p;
  278.     SFTypeList sfT;
  279.     EventRecord theEvent;
  280.     short eMask;
  281.     SFReply fileRep;
  282. #endif /* THINK_C */
  283.     int a;
  284.  
  285.     for (a = 0;  a < 4;  ++a)
  286.         rghCursor[a] = GetCursor(a+128);
  287.     giCursor = 0;
  288.  
  289. #ifdef THINK_C   
  290.     for (a = 0;  a < 30;  ++a)
  291.         argstr[a] = &args[a*64];
  292. start:
  293.     tflag=vflag=cflag=aflag=jflag=U_flag=quietflg=fflag=uflag=zflag = 0;
  294.     local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
  295. /*  extd_local_sig[1] = '\0';  */
  296.     error = FALSE;
  297.  
  298.     argc = ccommand(&argv);
  299.     SetPt(&p, 40, 40);
  300.  
  301.     SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep);
  302.     if (fileRep.good) {
  303.         macfstest(fileRep.vRefNum);
  304.         ResolveMacVol(fileRep.vRefNum, &gnVRefNum, &glDirID, NULL);
  305.         for (a = 1;  a < argc;  ++a)
  306.             if (argv[a][0] == '-')
  307.                 BlockMove(argv[a], argstr[a], (strlen(argv[a]) > 63) ? 64 :
  308.                    strlen(argv[a])+1);
  309.             else
  310.                 break;
  311.         PtoCstr((char *)fileRep.fName);
  312.         strcpy(argstr[a], (char *)fileRep.fName);
  313.         for (;  a < argc;  ++a)
  314.             BlockMove(argv[a], argstr[a+1], (strlen(argv[a]) > 63) ? 64 :
  315.                strlen(argv[a])+1);
  316.         ++argc;
  317.         argv = argstr;
  318.  
  319.         if (hfsflag == FALSE)  /* can't support directories:  junk pathnames */
  320.             jflag = 1;
  321.     }
  322. #endif /* THINK_C */
  323. #endif /* MACOS */
  324.  
  325. /*---------------------------------------------------------------------------
  326.     Set signal handler for restoring echo, warn of zipfile corruption, etc.
  327.   ---------------------------------------------------------------------------*/
  328.  
  329.     signal(SIGINT, handler);
  330. #ifdef SIGTERM                 /* Amiga has no SIGTERM; maybe others */
  331.     signal(SIGTERM, handler);
  332. #endif
  333. #ifdef SIGBUS
  334.     signal(SIGBUS, handler);
  335. #endif
  336. #ifdef SIGSEGV
  337.     signal(SIGSEGV, handler);
  338. #endif
  339.  
  340. /*---------------------------------------------------------------------------
  341.     Debugging info for checking on structure padding:
  342.   ---------------------------------------------------------------------------*/
  343.  
  344. #ifdef DEBUG_STRUC
  345.     printf("local_file_hdr size: %X\n",
  346.            sizeof(local_file_hdr));
  347.     printf("local_byte_hdr size: %X\n",
  348.            sizeof(local_byte_hdr));
  349.     printf("actual size of local headers: %X\n", LREC_SIZE);
  350.  
  351.     printf("central directory header size: %X\n",
  352.            sizeof(cdir_file_hdr));
  353.     printf("central directory byte header size: %X\n",
  354.            sizeof(cdir_byte_hdr));
  355.     printf("actual size of central dir headers: %X\n", CREC_SIZE);
  356.  
  357.     printf("end central dir record size: %X\n",
  358.            sizeof(ecdir_rec));
  359.     printf("end central dir byte record size: %X\n",
  360.            sizeof(ec_byte_rec));
  361.     printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
  362. #endif /* DEBUG_STRUC */
  363.  
  364. /*---------------------------------------------------------------------------
  365.     Put environment-variable options into the queue, then rip through any
  366.     command-line options lurking about...
  367.   ---------------------------------------------------------------------------*/
  368.  
  369.     envargs(&argc, &argv, ENV_UNZIP);
  370.  
  371.     while (--argc > 0 && (*++argv)[0] == '-') {
  372.         s = argv[0] + 1;
  373.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  374.             switch (c) {
  375.                 case ('-'):
  376.                     ++negative;
  377.                     break;
  378.                 case ('a'):
  379.                     if (negative)
  380.                         aflag = FALSE, negative = 0;
  381.                     else
  382.                         aflag = TRUE;
  383.                     break;
  384. #if 0
  385.                 case ('b'):    /* force binary mode */
  386.                     if (negative)
  387.                         bflag = FALSE, negative = 0;
  388.                     else
  389.                         bflag = TRUE;
  390.                     break;
  391. #endif
  392.                 case ('c'):
  393.                     if (negative) {
  394.                         cflag = FALSE, negative = 0;
  395. #ifdef NATIVE
  396.                         aflag = FALSE;
  397. #endif
  398.                     } else {
  399.                         cflag = TRUE;
  400. #ifdef NATIVE
  401.                         aflag = TRUE;  /* so you can read it on the screen */
  402. #endif
  403.                     }
  404.                     break;
  405.                 case ('d'):    /* re-create directory structure (default) */
  406.                     if (negative)
  407.                         jflag = TRUE, negative = 0;
  408.                     break;
  409.                 case ('e'):    /* just ignore -e, -x options (extract) */
  410.                     break;
  411.                 case ('f'):    /* "freshen" (extract only newer files) */
  412.                     if (negative)
  413.                         fflag = uflag = FALSE, negative = 0;
  414.                     else
  415.                         fflag = uflag = TRUE;
  416.                     break;
  417.                 case ('j'):    /* junk pathnames/directory structure */
  418.                     if (negative)
  419.                         jflag = FALSE, negative = 0;
  420.                     else
  421.                         jflag = TRUE;
  422.                     break;
  423.                 case ('l'):
  424.                     if (negative) {
  425.                         vflag = MAX(vflag-negative,0);
  426.                         negative = 0;
  427.                     } else
  428.                         ++vflag;
  429.                     break;
  430.                 case ('n'):    /* don't overwrite any files */
  431.                     if (negative)
  432.                         overwrite_none = FALSE, negative = 0;
  433.                     else
  434.                         overwrite_none = TRUE;
  435.                     break;
  436.                 case ('o'):    /* OK to overwrite files without prompting */
  437.                     if (negative) {
  438.                         overwrite_all = MAX(overwrite_all-negative,0);
  439.                         force_flag = MAX(force_flag-negative,0);
  440.                         negative = 0;
  441.                     } else {
  442.                         ++overwrite_all;
  443.                         ++force_flag;  /* (share -o for now) force to cont. */
  444.                     }
  445.                     break;
  446.                 case ('p'):    /* pipes:  stdout, no tranlation, no messages */
  447.                     if (negative) {
  448.                         cflag = FALSE;
  449.                         quietflg = MAX(quietflg-999,0);
  450.                         negative = 0;
  451.                     } else {
  452.                         cflag = TRUE;
  453.                         quietflg += 999;
  454.                     }
  455.                     break;
  456.                 case ('q'):    /* quiet:  fewer comments/messages */
  457.                     if (negative) {
  458.                         quietflg = MAX(quietflg-negative,0);
  459.                         negative = 0;
  460.                     } else
  461.                         ++quietflg;
  462.                     break;
  463. #ifdef DOS_OS2
  464.                 case ('s'):    /* spaces in filenames:  allow by default */
  465.                     if (negative)
  466.                         sflag = TRUE, negative = 0;
  467.                     else
  468.                         sflag = FALSE;
  469.                     break;
  470. #endif
  471.                 case ('t'):
  472.                     if (negative)
  473.                         tflag = FALSE, negative = 0;
  474.                     else
  475.                         tflag = TRUE;
  476.                     break;
  477.                 case ('U'):    /* Uppercase (don't convert to all-lower) */
  478.                     if (negative)
  479.                         U_flag = FALSE, negative = 0;
  480.                     else
  481.                         U_flag = TRUE;
  482.                     break;
  483.                 case ('u'):    /* update (extract only new and newer files) */
  484.                     if (negative)
  485.                         uflag = FALSE, negative = 0;
  486.                     else
  487.                         uflag = TRUE;
  488.                     break;
  489.                 case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
  490.                     if (negative)
  491.                         V_flag = FALSE, negative = 0;
  492.                     else
  493.                         V_flag = TRUE;
  494.                     break;
  495.                 case ('v'):    /* verbose */
  496.                     if (negative) {
  497.                         vflag = MAX(vflag-negative,0);
  498.                         negative = 0;
  499.                     } else if (vflag)
  500.                         ++vflag;
  501.                     else
  502.                         vflag = 2;
  503.                     break;
  504. #ifdef VMS
  505.                 case ('X'):   /* restore owner/protection info (need privs?) */
  506.                     if (negative)
  507.                         secinf = FALSE, negative = 0;
  508.                     else
  509.                         secinf = TRUE;
  510.                     break;
  511. #endif /* VMS */
  512.                 case ('x'):    /* extract:  default */
  513.                     break;
  514.                 case ('z'):    /* display only the archive comment */
  515.                     if (negative) {
  516.                         zflag -= negative;
  517.                         negative = 0;
  518.                     } else
  519.                         ++zflag;
  520.                     break;
  521.                 default:
  522.                     error = TRUE;
  523.                     break;
  524.  
  525.             } /* end switch */
  526.         } /* end while (not end of argument string) */
  527.     } /* end while (not done with switches) */
  528.  
  529. /*---------------------------------------------------------------------------
  530.     Make sure we aren't trying to do too many things here.  [This seems like
  531.     kind of a brute-force way to do things; but aside from that, isn't the
  532.     -a option useful when listing the directory (i.e., for reading zipfile
  533.     comments)?  It's a modifier, not an action in and of itself, so perhaps
  534.     it should not be included in the test--certainly, in the case of zipfile
  535.     testing, it can just be ignored.]
  536.   ---------------------------------------------------------------------------*/
  537.  
  538.     if ((aflag && tflag) || (aflag && vflag) || (cflag && tflag) ||
  539.         (cflag && uflag) || (cflag && vflag) || (tflag && uflag) ||
  540.         (tflag && vflag) || (uflag && vflag) || (fflag && overwrite_none)) {
  541.         fprintf(stderr, "error:\
  542.   -at, -av, -ct, -cu, -cv, -fn, -tu, -tv, -uv combinations not allowed\n");
  543.         error = TRUE;
  544.     }
  545.     if (quietflg && (zflag > 0))  /* quietflg makes no sense */
  546.         quietflg = 0;
  547.     if (overwrite_all && overwrite_none) {
  548.         fprintf(stderr, "caution:  both -n and -o specified; ignoring -o\n");
  549.         overwrite_all = FALSE;
  550.     }
  551.     if ((argc-- == 0) || error)
  552.         RETURN(usage(error));
  553.  
  554. /*---------------------------------------------------------------------------
  555.     Now get the zipfile name from the command line and see if it exists as a
  556.     regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  557.     immediately check to see if this results in a good name, but we will do so
  558.     later.  In the meantime, see if there are any member filespecs on the com-
  559.     mand line, and if so, set the filename pointer to point at them.
  560.   ---------------------------------------------------------------------------*/
  561.  
  562.     strcpy(zipfn, *argv++);
  563.     if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
  564.         strcat(zipfn, ZSUFX);
  565. #ifdef UNIX  /* no extension on Unix exe's--might find zip, not zip.zip; etc. */
  566.     else if (statbuf.st_mode & S_IXUSR)
  567.         fprintf(stderr, "note:  file [ %s ] may be an executable\n\n", zipfn);
  568. #endif
  569.  
  570.     if (stat(zipfn, &statbuf)) {   /* try again */
  571.         fprintf(stderr, "error:  can't find zipfile [ %s ]\n", zipfn);
  572.         RETURN(PK_NOZIP);
  573.     } else
  574.         ziplen = statbuf.st_size;
  575.  
  576.     filespecs = argc;
  577.     xfilespecs = 0;
  578.  
  579.     if (argc != 0) {
  580.         char **pp = argv-1;
  581. #ifdef DOS_OS2
  582.         char *q;
  583.  
  584.         pfnames = argv;
  585.         /* convert MSDOS-style directory separators to Unix-style ones */
  586.         while (*pfnames != NULL) {
  587.             for (q = *pfnames;  *q;  ++q)
  588.                 if (*q == '\\')
  589.                     *q = '/';
  590.             ++pfnames;
  591.         }
  592. #endif
  593.         pfnames = argv;
  594.         while (*++pp)
  595.             if (!strcmp(*pp, "-x")) {
  596.                 if (pp > argv) {
  597.                     *pp = 0;           /* terminate pfnames */
  598.                     filespecs = pp - pfnames;
  599.                 } else {
  600.                     pfnames = fnames;  /* defaults */
  601.                     filespecs = 0;
  602.                 }
  603.                 pxnames = pp + 1;      /* excluded-names ptr starts after -x */
  604.                 xfilespecs = argc - filespecs - 1;
  605.                 break;                 /* skip rest of args */
  606.             }
  607.         process_all_files = FALSE;
  608.     } else
  609.         process_all_files = TRUE;       /* for speed */
  610.  
  611. /*---------------------------------------------------------------------------
  612.     Okey dokey, we have everything we need to get started.  Let's roll.
  613.   ---------------------------------------------------------------------------*/
  614.  
  615.     inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
  616.     outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string termin. */
  617. #ifndef DOS_OS2
  618.     if (aflag)                  /* if need an ascebc scratch, */
  619.         outout = (uch *)malloc(OUTBUFSIZ);
  620.     else                        /*  allocate it... */
  621. #endif /* !DOS_OS2 */
  622.         outout = outbuf;        /*  else just point to outbuf */
  623.  
  624.     if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL) ||
  625.         (outout == (uch *)NULL)) {
  626.         fprintf(stderr, "error:  can't allocate unzip buffers\n");
  627.         RETURN(PK_MEM);
  628.     }
  629.     hold = &inbuf[INBUFSIZ];    /* to check for boundary-spanning signatures */
  630.  
  631.     RETURN(process_zipfile());  /* keep passing errors back... */
  632.  
  633. } /* end main() */
  634.  
  635.  
  636.  
  637.  
  638.  
  639. /**********************/
  640. /*  Function usage()  */
  641. /**********************/
  642.  
  643. int usage(error)   /* return PK-type error code */
  644.     int error;
  645. {
  646. #ifdef VMS
  647. #  define QUOT '\"'
  648. #  define EXAMPLE2 "vms.c"
  649. #  define EXAMPLE1 \
  650. "unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS"
  651. #else
  652. #  define QUOT ' '
  653. #  define EXAMPLE2 "ReadMe"
  654. #  define EXAMPLE1 \
  655. "unzip -p foo | more  => send contents of foo.zip via pipe into program more"
  656. #endif
  657.  
  658. #ifdef NATIVE
  659. #ifdef EBCDIC
  660.     char *astring = "-a  convert ASCII to EBCDIC";
  661. #else /* !EBCDIC */
  662.     char *astring = "-a  convert ASCII to native chars";
  663. #endif /* ?EBCDIC */
  664. /*  char *astring = "-a  convert ASCII to " NATIVE;  (ANSI C concatenation)  */
  665.     char *loc_str = "";
  666. #else /* !NATIVE */
  667. #ifdef DOS_OS2
  668.     char *astring = "-a  convert text (LF => CR LF)";
  669.     char *loc_str = " -s  spaces in filenames => _";
  670. #else /* !DOS_OS2 */
  671. #ifdef MACOS
  672.     char *astring = "-a  convert text (CR LF => CR)";
  673.     char *loc_str = "";
  674. #else /* !MACOS:  UNIX, VMS, etc. */
  675.     char *astring = "-a  convert text (CR LF => LF)";
  676. #ifdef VMS
  677.     char *loc_str = "\"-X\" restore owner/protection info";
  678. #else /* !VMS */
  679.     char *loc_str = "";
  680. #endif /* ?VMS */
  681. #endif /* ?MACOS */
  682. #endif /* ?DOS_OS2 */
  683. #endif /* ?NATIVE */
  684.     FILE *usagefp;
  685.  
  686.  
  687. /*---------------------------------------------------------------------------
  688.     If user requested usage, send it to stdout; else send to stderr.
  689.   ---------------------------------------------------------------------------*/
  690.  
  691.     if (error)
  692.         usagefp = (FILE *)stderr;
  693.     else
  694.         usagefp = (FILE *)stdout;
  695.  
  696.     fprintf(usagefp, "\
  697. UnZip:  Zipfile Extract %s;  (c) 1989 S.H.Smith and others\n\
  698. Versions 3.0 and later by Info-ZIP.  Bug reports ONLY to zip-bugs@cs.ucla.edu.\
  699. \n\n", VERSION);
  700.  
  701.     fprintf(usagefp, "\
  702. Usage: unzip [ -options[modifiers] ] file[.zip] [list] [-x xlist]\n\
  703.   Default action is to extract all specified files except for those in xlist.\n\
  704.   -c  extract files to stdout/screen (CRT)   -l  list files (short format)\n\
  705.   -p  extract files to pipe, no messages     -v  list files (verbose format)\n\
  706.   -f  freshen existing files, create none    -t  test compressed archive data\n\
  707.   -u  update files, create if necessary      -z  display archive comment\n\
  708.                                              -x  exclude files which follow\n\
  709. modifiers:\n\
  710.   -n  never overwrite existing files        %s\n", loc_str);
  711.     fprintf(usagefp, "\
  712.   -o  overwrite files WITHOUT prompting      %s\n\
  713.   -j  junk paths (don't make directories)   %c-U%c don't make names lowercase\n\
  714.   -q  quiet mode (-qq => quieter)           %c-V%c retain VMS version numbers\
  715. \n\n\
  716. Examples: (See unzip.doc for more information)\n\
  717.   unzip data1 -x joe   => extract all files except joe from zipfile data1.zip\n\
  718.   %s\n\
  719.   unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n",
  720.     astring, QUOT,QUOT, QUOT,QUOT, EXAMPLE1, EXAMPLE2,EXAMPLE2);
  721.  
  722.     if (error)
  723.         return PK_PARAM;
  724.     else
  725.         return PK_COOL;     /* just wanted usage screen: no error */
  726.  
  727. } /* end function usage() */
  728.  
  729. #endif /* ?MSWIN */
  730.  
  731.  
  732.  
  733.  
  734. /********************************/
  735. /*  Function process_zipfile()  */
  736. /********************************/
  737.  
  738. int process_zipfile()    /* return PK-type error code */
  739. {
  740.     int error, error_in_archive;
  741.  
  742.  
  743. /*---------------------------------------------------------------------------
  744.     Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
  745.     lation, which would corrupt the bitstreams.
  746.   ---------------------------------------------------------------------------*/
  747.  
  748. #ifdef VMS
  749.     if (check_format())         /* check for variable-length format */
  750.         return PK_ERR;
  751. #endif /* VMS */
  752.  
  753.     if (open_input_file())      /* this should never happen, given the */
  754.         return PK_NOZIP;        /*   stat() test in main(), but... */
  755.  
  756. /*---------------------------------------------------------------------------
  757.     Reconstruct the various PK signature strings, and find and process the
  758.     end-of-central-directory header.  Need only check last 65557 bytes of
  759.     zipfile:  comment may be up to 65535, end-of-central-directory record
  760.     is 18 bytes, and signature itself is 4 bytes.  Add some to allow for
  761.     appended garbage.
  762.   ---------------------------------------------------------------------------*/
  763.  
  764.     strcat(local_hdr_sig, LOCAL_HDR_SIG);
  765.     strcat(central_hdr_sig, CENTRAL_HDR_SIG);
  766.     strcat(end_central_sig, END_CENTRAL_SIG);
  767. /*  strcat(extd_local_sig, EXTD_LOCAL_SIG);  */
  768.  
  769.     if ((error_in_archive = find_end_central_dir(MIN(ziplen,66000L))) != 0  ||
  770.         (error_in_archive = process_end_central_dir()) > PK_WARN) {
  771.         close(zipfd);
  772.         return error_in_archive;
  773.     }
  774.     if (zflag > 0) {
  775.         close(zipfd);
  776.         return error_in_archive;
  777.     }
  778.  
  779. /*---------------------------------------------------------------------------
  780.     Test the end-of-central-directory info for incompatibilities and incon-
  781.     sistencies.
  782.   ---------------------------------------------------------------------------*/
  783.  
  784.     error = ((ecrec.number_this_disk == 1) &&
  785.              (ecrec.num_disk_with_start_central_dir == 1));
  786.  
  787.     if ((ecrec.number_this_disk == 0) || error) {
  788.         if (error) {
  789.             fprintf(stderr,
  790.      "\n     Warning:  zipfile claims to be disk 2 of a two-part archive;\n\
  791.      attempting to process anyway.  If no further errors occur, this\n\
  792.      archive was probably created by PAK v2.51 or earlier.  This bug\n\
  793.      was reported to NoGate in March 1991 and was supposed to have been\n\
  794.      fixed by mid-1991; as of mid-1992 it still hadn't been.\n\n");
  795.             error_in_archive = PK_WARN;
  796.         }
  797.         if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) {
  798.             fprintf(stderr, "\nerror:  missing %ld bytes in zipfile (\
  799. attempting to process anyway)\n\n", -extra_bytes);
  800.             error_in_archive = PK_ERR;
  801.         } else if (extra_bytes > 0) {
  802.             if ((ecrec.offset_start_central_directory == 0) &&
  803.                 (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  804.             {
  805.                 fprintf(stderr, "\nerror:  NULL central directory offset (\
  806. attempting to process anyway)\n\n");
  807.                 ecrec.offset_start_central_directory = extra_bytes;
  808.                 extra_bytes = 0;
  809.                 error_in_archive = PK_ERR;
  810.             } else {
  811.                 fprintf(stderr, "\nwarning:  extra %ld bytes at beginning or\
  812.  within zipfile\n          (attempting to process anyway)\n\n", extra_bytes);
  813.                 error_in_archive = PK_WARN;
  814.             }
  815.         }
  816.  
  817.     /*-----------------------------------------------------------------------
  818.         Check for empty zipfile and exit now if so.
  819.       -----------------------------------------------------------------------*/
  820.  
  821.         if (expect_ecrec_offset == 0L  &&  ecrec.size_central_directory == 0) {
  822.             fprintf(stderr, "warning:  zipfile is empty\n");
  823.             close(zipfd);
  824.             return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
  825.         }
  826.  
  827.     /*-----------------------------------------------------------------------
  828.         Compensate for missing or extra bytes, and seek to where the start
  829.         of central directory should be.  If header not found, uncompensate
  830.         and try again (necessary for at least some Atari archives created
  831.         with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
  832.       -----------------------------------------------------------------------*/
  833.  
  834.         LSEEK( ecrec.offset_start_central_directory )
  835.         if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
  836.             longint tmp = extra_bytes;
  837.  
  838.             extra_bytes = 0;
  839.             LSEEK( ecrec.offset_start_central_directory )
  840.             if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
  841.                 fprintf(stderr,
  842.             "error:  start of central directory not found; zipfile corrupt.\n");
  843.                 fprintf(stderr, ReportMsg);
  844.                 close(zipfd);
  845.                 return PK_BADERR;
  846.             }
  847.             fprintf(stderr, "error:  reported length of central directory is \
  848. %d bytes too long\n        (Atari STZIP zipfile?  J.H.Holm ZIPSPLIT 1.1 \
  849. zipfile?).\n        Compensating...\n\n", -tmp);
  850.             error_in_archive = PK_ERR;
  851.         }
  852.  
  853.     /*-----------------------------------------------------------------------
  854.         Seek to the start of the central directory one last time, since we
  855.         have just read the first entry's signature bytes; then list, extract
  856.         or test member files as instructed, and close the zipfile.
  857.       -----------------------------------------------------------------------*/
  858.  
  859.         LSEEK( ecrec.offset_start_central_directory )
  860.         if (vflag)
  861.             error = list_files();               /* LIST 'EM */
  862.         else
  863.             error = extract_or_test_files();    /* EXTRACT OR TEST 'EM */
  864.         if (error > error_in_archive)   /* don't overwrite stronger error */
  865.             error_in_archive = error;   /*  with (for example) a warning */
  866.     } else {
  867.         fprintf(stderr, "\nerror:  zipfile is part of multi-disk archive \
  868. (sorry, not supported).\n");
  869.         error_in_archive = PK_FIND;
  870.     }
  871.  
  872.     close(zipfd);
  873.     return error_in_archive;
  874.  
  875. } /* end function process_zipfile() */
  876.  
  877.  
  878.  
  879.  
  880.  
  881. /**************************************/
  882. /* Function process_end_central_dir() */
  883. /**************************************/
  884.  
  885. int process_end_central_dir()    /* return PK-type error code */
  886. {
  887.     int error = PK_COOL;
  888.  
  889.  
  890. /*---------------------------------------------------------------------------
  891.     Get the zipfile comment (up to 64KB long), if any, and print it out.
  892.     Then position the file pointer to the beginning of the central directory
  893.     and fill buffer.
  894.   ---------------------------------------------------------------------------*/
  895.  
  896. #ifdef MSWIN
  897.     cchComment = ecrec.zipfile_comment_length; /* save for comment button */
  898.     if (ecrec.zipfile_comment_length && (zflag > 0)) {
  899. #else /* !MSWIN */
  900.     if (ecrec.zipfile_comment_length && !(zflag < 0) && !quietflg) {
  901.         if (zflag == 0)
  902.             printf("[%s] comment:\n", zipfn);
  903. #endif /* ?MSWIN */
  904.         if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  905.             fprintf(stderr, "\ncaution:  zipfile comment truncated\n");
  906.             error = PK_WARN;
  907.         }
  908.     }
  909.     return error;
  910.  
  911. } /* end function process_end_central_dir() */
  912.  
  913.  
  914.  
  915.  
  916.  
  917. /* also referenced in UpdateListBox() in updatelb.c (Windows version) */
  918. char *Headers[][2] = {
  919.     {" Length    Date    Time    Name",
  920.      " ------    ----    ----    ----"},
  921.     {" Length  Method   Size  Ratio   Date    Time   CRC-32     Name",
  922.      " ------  ------   ----  -----   ----    ----   ------     ----"}
  923. };
  924.  
  925. /*************************/
  926. /* Function list_files() */
  927. /*************************/
  928.  
  929. int list_files()    /* return PK-type error code */
  930. {
  931.     int do_this_file=FALSE, ratio, error, error_in_archive=PK_COOL;
  932.     int which_hdr=(vflag>1), date_format;
  933.     ush j, yr, mo, dy, hh, mm, members=0;
  934.     ulg tot_csize=0L, tot_ucsize=0L;
  935. #ifdef OS2
  936.     ulg tot_easize=0L, tot_eafiles=0L, ea_size;
  937. #endif
  938. #ifdef MSWIN
  939.     PSTR psLBEntry;  /* list box entry */
  940. #endif
  941.     min_info info;
  942.     static char *method[NUM_METHODS+1] =
  943.         {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
  944.          "Implode", "Token", "Deflate", unkn};
  945.  
  946.  
  947.  
  948. /*---------------------------------------------------------------------------
  949.     Unlike extract_or_test_files(), this routine confines itself to the cen-
  950.     tral directory.  Thus its structure is somewhat simpler, since we can do
  951.     just a single loop through the entire directory, listing files as we go.
  952.  
  953.     So to start off, print the heading line and then begin main loop through
  954.     the central directory.  The results will look vaguely like the following:
  955.  
  956.   Length  Method   Size  Ratio   Date    Time   CRC-32     Name ("^" ==> case
  957.   ------  ------   ----  -----   ----    ----   ------     ----   conversion)
  958.    44004  Implode  13041  71%  11-02-89  19:34  8b4207f7   Makefile.UNIX
  959.     3438  Shrunk    2209  36%  09-15-90  14:07  a2394fd8  ^dos-file.ext
  960.   ---------------------------------------------------------------------------*/
  961.  
  962.     pInfo = &info;
  963.     date_format = dateformat();
  964.  
  965. #ifndef MSWIN
  966.     if (quietflg < 2)
  967.         if (U_flag)
  968.             printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
  969.         else
  970.             printf("%s (\"^\" ==> case\n%s   conversion)\n", 
  971.               Headers[which_hdr][0], Headers[which_hdr][1]);
  972. #endif /* !MSWIN */
  973.  
  974.     for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
  975.  
  976.         if (readbuf(sig, 4) <= 0)
  977.             return PK_EOF;
  978.         if (strncmp(sig, central_hdr_sig, 4)) {  /* just to make sure */
  979.             fprintf(stderr, CentSigMsg, j);  /* sig not found */
  980.             fprintf(stderr, ReportMsg);   /* check binary transfers */
  981.             return PK_BADERR;
  982.         }
  983.         /* process_cdir_file_hdr() sets pInfo->lcflag: */
  984.         if ((error = process_cdir_file_hdr()) != PK_COOL)
  985.             return error;       /* only PK_EOF defined */
  986.  
  987.         /*
  988.          * We could DISPLAY the filename instead of storing (and possibly trun-
  989.          * cating, in the case of a very long name) and printing it, but that
  990.          * has the disadvantage of not allowing case conversion--and it's nice
  991.          * to be able to see in the listing precisely how you have to type each
  992.          * filename in order for unzip to consider it a match.  Speaking of
  993.          * which, if member names were specified on the command line, check in
  994.          * with match() to see if the current file is one of them, and make a
  995.          * note of it if it is.
  996.          */
  997.  
  998.         if ((error = do_string(crec.filename_length, FILENAME)) != PK_COOL) {
  999.             error_in_archive = error;             /*  ^--(uses pInfo->lcflag) */
  1000.             if (error > PK_WARN)   /* fatal:  can't continue */
  1001.                 return error;
  1002.         }
  1003.         if (extra_field != (uch *)NULL)
  1004.             free(extra_field);
  1005.         extra_field = (uch *)NULL;
  1006.         if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) {
  1007.             error_in_archive = error;  
  1008.             if (error > PK_WARN)      /* fatal */
  1009.                 return error;
  1010.         }
  1011.         if (!process_all_files) {   /* check if specified on command line */
  1012.             char **pfn = pfnames-1;
  1013.  
  1014.             do_this_file = FALSE;
  1015.             while (*++pfn)
  1016.                 if (match(filename, *pfn)) {
  1017.                     do_this_file = TRUE;
  1018.                     break;       /* found match, so stop looping */
  1019.                 }
  1020.             if (do_this_file) {  /* check if this is an excluded file */
  1021.                 char **pxn = pxnames-1;
  1022.  
  1023.                 while (*++pxn)
  1024.                     if (match(filename, *pxn)) {
  1025.                         do_this_file = FALSE;
  1026.                         break;
  1027.                     }
  1028.             }
  1029.         }
  1030.         /*
  1031.          * If current file was specified on command line, or if no names were
  1032.          * specified, do the listing for this file.  Otherwise, get rid of the
  1033.          * file comment and go back for the next file.
  1034.          */
  1035.  
  1036.         if (process_all_files || do_this_file) {
  1037.  
  1038.             yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % (unsigned)100;
  1039.             mo = (crec.last_mod_file_date >> 5) & 0x0f;
  1040.             dy = crec.last_mod_file_date & 0x1f;
  1041.  
  1042.             /* twist date so it displays according to national convention */
  1043.             switch (date_format) {
  1044.                 case DF_YMD:
  1045.                     hh = mo; mo = yr; yr = dy; dy = hh; break;
  1046.                 case DF_DMY:
  1047.                     hh = mo; mo = dy; dy = hh;
  1048.             }
  1049.             hh = (crec.last_mod_file_time >> 11) & 0x1f;
  1050.             mm = (crec.last_mod_file_time >> 5) & 0x3f;
  1051.  
  1052.             csize = (longint) crec.csize;
  1053.             ucsize = (longint) crec.ucsize;
  1054.             if (crec.general_purpose_bit_flag & 1)
  1055.                 csize -= 12;    /* if encrypted, don't count encrypt hdr */
  1056.  
  1057.             ratio = (ucsize == 0) ? 0 :   /* .zip can have 0-length members */
  1058.                 ((ucsize > 2000000L) ?    /* risk signed overflow if mult. */
  1059.                 (int) ((ucsize-csize) / (ucsize/1000L)) + 5 :   /* big */
  1060.                 (int) ((1000L*(ucsize-csize)) / ucsize) + 5);   /* small */
  1061.  
  1062. #if 0       /* GRR/Euro:  add this?  define p above */
  1063. #if defined(DOS_OS2) || defined(UNIX)
  1064.             for (p = filename;  *p;  ++p)
  1065.                 if (!isprint(*p))
  1066.                     *p = '?';  /* change non-printable chars to '?' */
  1067. #endif /* DOS_OS2 || UNIX */
  1068. #endif /* 0 */
  1069.  
  1070. #ifdef MSWIN
  1071. #ifdef NEED_EARLY_REDRAW
  1072.             /* turn on listbox redrawing just before adding last line */
  1073.             if (j == (ecrec.total_entries_central_dir-1))
  1074.                 (void)SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);
  1075. #endif /* NEED_EARLY_REDRAW */
  1076.             psLBEntry =
  1077.               (PSTR)LocalAlloc(LMEM_FIXED, FILNAMSIZ+LONG_FORM_FNAME_INX);
  1078.             switch (which_hdr) {
  1079.                 case 0:   /* short form */
  1080.                     OemToAnsi(filename, filename);  /* translate to ANSI */
  1081.                     wsprintf(psLBEntry, "%7ld  %02u-%02u-%02u  %02u:%02u  %c%s",
  1082.                       (long)ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '),
  1083.                       (LPSTR)filename);
  1084.                     SendMessage(hWndList, LB_ADDSTRING, 0,
  1085.                       (LONG)(LPSTR)psLBEntry);
  1086.                     break;
  1087.                 case 1:   /* verbose */
  1088.                     OemToAnsi(filename, filename);  /* translate to ANSI */
  1089.                     wsprintf(psLBEntry, 
  1090.                  "%7ld  %-7s%7ld %3d%%  %02u-%02u-%02u  %02u:%02u  %08lx  %c%s",
  1091.                       (long)ucsize, (LPSTR)method[methnum], (long)csize,
  1092.                       ratio/10, mo, dy, yr, hh, mm, (unsigned long)crec.crc32,
  1093.                       (pInfo->lcflag?'^':' '), (LPSTR)filename);
  1094.                     SendMessage(hWndList, LB_ADDSTRING, 0,
  1095.                       (LONG)(LPSTR)psLBEntry);
  1096.             }
  1097.             LocalFree((HANDLE)psLBEntry);
  1098. #else /* !MSWIN */
  1099.             if (which_hdr == 0)   /* short form */
  1100.                 printf("%7ld  %02u-%02u-%02u  %02u:%02u  %c%s\n", ucsize,
  1101.                   mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '), filename);
  1102.             else                  /* verbose */
  1103.                 printf(
  1104.               "%7ld  %-7s%7ld %3d%%  %02u-%02u-%02u  %02u:%02u  %08lx  %c%s\n",
  1105.                   ucsize, method[methnum], csize, ratio/10, mo, dy, yr,
  1106.                   hh, mm, crec.crc32, (pInfo->lcflag?'^':' '), filename);
  1107. #endif /* ?MSWIN */
  1108.  
  1109.             error = do_string(crec.file_comment_length, QCOND? DISPLAY : SKIP);
  1110.             if (error) {
  1111.                 error_in_archive = error;  /* might be just warning */
  1112.                 if (error > PK_WARN)       /* fatal */
  1113.                     return error;
  1114.             }
  1115.             tot_ucsize += (ulg)ucsize;
  1116.             tot_csize += (ulg)csize;
  1117.             ++members;
  1118. #ifdef OS2
  1119.             if ((ea_size = SizeOfEAs(extra_field)) != 0) {
  1120.                 tot_easize += ea_size;
  1121.                 tot_eafiles++;
  1122.             }
  1123. #endif
  1124.         } else {        /* not listing this file */
  1125.             SKIP_(crec.file_comment_length)
  1126.         }
  1127.     } /* end for-loop (j: files in central directory) */
  1128.  
  1129. /*---------------------------------------------------------------------------
  1130.     Print footer line and totals (compressed size, uncompressed size, number
  1131.     of members in zipfile).
  1132.   ---------------------------------------------------------------------------*/
  1133.  
  1134.     ratio = (tot_ucsize == 0) ? 
  1135.         0 : ((tot_ucsize > 4000000L) ?   /* risk unsigned overflow if mult. */
  1136.         (int)((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 :
  1137.         (int)((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5 );
  1138.  
  1139.     if (quietflg < 2) {
  1140. #ifdef MSWIN
  1141.         /* Display just the totals since the dashed lines get displayed
  1142.          * in UpdateListBox(). Get just enough space to display total. */
  1143.         if (which_hdr)   /* verbose */
  1144.             wsprintf(lpumb->szTotalsLine, 
  1145.               "%7lu         %7lu %3d%%                              %-7u", 
  1146.               (ulg)tot_ucsize, (ulg)tot_csize, ratio/10, members);
  1147.         else             /* short */
  1148.             wsprintf(lpumb->szTotalsLine, "%7lu                    %-7u", 
  1149.               (ulg)tot_ucsize, members);
  1150. #else /* !MSWIN */
  1151.         if (which_hdr)   /* verbose */
  1152.             printf(" ------          ------  ---                \
  1153.               -------\n%7lu         %7lu %3d%%                \
  1154.               %-7u\n", tot_ucsize, tot_csize, ratio/10, members);
  1155.         else             /* short */
  1156.             printf(" ------                    -------%s\n%7lu      \
  1157.               %-7u\n", tot_ucsize, members);
  1158. #endif /* ?MSWIN */
  1159. #ifdef OS2
  1160.         if (tot_eafiles && tot_easize)
  1161.             printf("\n%ld file%s %ld bytes of EA's attached.\n", tot_eafiles, 
  1162.               tot_eafiles == 1 ? " has" : "s have a total of", tot_easize);
  1163. #endif
  1164.     }
  1165. /*---------------------------------------------------------------------------
  1166.     Double check that we're back at the end-of-central-directory record.
  1167.   ---------------------------------------------------------------------------*/
  1168.  
  1169.     readbuf(sig, 4);
  1170.     if (strncmp(sig, end_central_sig, 4)) {     /* just to make sure again */
  1171.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  1172.         error_in_archive = PK_WARN;
  1173.     }
  1174.     return error_in_archive;
  1175.  
  1176. } /* end function list_files() */
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182. /**************************************/
  1183. /*  Function process_cdir_file_hdr()  */
  1184. /**************************************/
  1185.  
  1186. int process_cdir_file_hdr()    /* return PK-type error code */
  1187. {
  1188.     int error;
  1189.  
  1190.  
  1191. /*---------------------------------------------------------------------------
  1192.     Get central directory info, save host and method numbers, and set flag
  1193.     for lowercase conversion of filename, depending on the OS from which the
  1194.     file is coming.
  1195.   ---------------------------------------------------------------------------*/
  1196.  
  1197.     if ((error = get_cdir_file_hdr()) != 0)
  1198.         return error;
  1199.  
  1200.     pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
  1201. /*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
  1202.     methnum = MIN(crec.compression_method, NUM_METHODS);
  1203.     if (methnum == NUM_METHODS)
  1204.         sprintf(unkn, "Unk:%03d", crec.compression_method);
  1205.  
  1206.     pInfo->lcflag = 0;
  1207.     if (!U_flag)   /* as long as user hasn't specified case-preservation */
  1208.         switch (pInfo->hostnum) {
  1209.             case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
  1210.             case VM_CMS_:     /* all caps? */
  1211.             case CPM_:        /* like DOS, right? */
  1212.         /*  case ATARI_:      ? */
  1213.         /*  case Z_SYSTEM_:   ? */
  1214.             case TOPS20_:
  1215.         /*  case QDOS_:       ? */
  1216.                 pInfo->lcflag = 1;   /* convert filename to lowercase */
  1217.                 break;
  1218.  
  1219.         /*  case VMS_:   VMS Zip converts filenames to lowercase */
  1220.             default:     /* AMIGA_, UNIX_, (ATARI_), FS_HPFS_, MAC_, */
  1221.                 break;   /*  (Z_SYSTEM_), FS_NTFS_:  no conversion */
  1222.         }
  1223.  
  1224.     return PK_COOL;
  1225.  
  1226. } /* end function process_cdir_file_hdr() */
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232. /***************************************/
  1233. /*  Function process_local_file_hdr()  */
  1234. /***************************************/
  1235.  
  1236. int process_local_file_hdr()    /* return PK-type error code */
  1237. {
  1238.     local_byte_hdr byterec;
  1239.  
  1240.  
  1241. /*---------------------------------------------------------------------------
  1242.     Read the next local file header and do any necessary machine-type con-
  1243.     versions (byte ordering, structure padding compensation--do so by copy-
  1244.     ing the data from the array into which it was read (byterec) to the
  1245.     usable struct (lrec)).
  1246.   ---------------------------------------------------------------------------*/
  1247.  
  1248.     if (readbuf((char *)byterec, LREC_SIZE) <= 0)
  1249.         return PK_EOF;
  1250.  
  1251.     lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
  1252.     lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
  1253.  
  1254.     lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
  1255.     lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
  1256.     lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
  1257.     lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
  1258.     lrec.crc32 = makelong(&byterec[L_CRC32]);
  1259.     lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
  1260.     lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
  1261.     lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
  1262.     lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
  1263.  
  1264.     csize = (longint) lrec.csize;
  1265.     ucsize = (longint) lrec.ucsize;
  1266.  
  1267.     if ((lrec.general_purpose_bit_flag & 8) != 0) {
  1268.         /* can't trust local header, use central directory: */
  1269.         lrec.crc32 = pInfo->crc;
  1270.         csize = (longint)(lrec.csize = pInfo->compr_size);
  1271.     }
  1272.  
  1273.     return PK_COOL;
  1274.  
  1275. } /* end function process_local_file_hdr() */
  1276.